import json
import pickle
import time
from collections import OrderedDict
from functools import wraps


def log_decorator(log_path="log.txt"):
  def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
      call_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
      log_entry = {
        "time": call_time,
        "function": func.__name__,
        "doc": func.__doc__,
        "args": args,
        "kwargs": kwargs,
        "result": "",
      }
      result = func(*args, **kwargs)
      log_entry["result"] = result

      #写入文件
      with open(log_path, "a", encoding="utf-8") as f:
        f.write(json.dumps(log_entry, ensure_ascii=False) + "\n")

      return result
    return wrapper
  return decorator

def cache_decorator(
  cache_path="cache.txt",
  max_size=10
):
  def decorator(func):
    try:
      with open(cache_path, "r", encoding="utf-8") as f:
        cache = OrderedDict(json.load(f))
    except (FileNotFoundError, json.decoder.JSONDecodeError):
      cache = OrderedDict()

    print(cache)

    @wraps(func)
    def wrapper(*args, **kwargs):
      key = json.dumps({"args": args, "kwargs": kwargs}, sort_keys=True)

      result = None
      if key in cache:
        print(f'命中缓存：{key} -> {cache[key]}')
        cache.move_to_end(key)
        result = cache[key]
      else:
        if len(cache) >= max_size:
          oldest_key = next(iter(cache)) # 获取最久没有用过的key
          print(f"[CACHE]缓存已满，移除许久未用的key：{oldest_key}")
          cache.pop(oldest_key)
        result = func(*args, **kwargs)
        cache[key] = result

      with open(cache_path, "w", encoding="utf-8") as f:
        json.dump(list(cache.items()), f, ensure_ascii=False, indent=2)

      return result
    return wrapper

  return decorator



@cache_decorator(
  cache_path="../data/cache.json",
  max_size=3
)
@log_decorator(log_path="../data/log.txt")
def compute(x, y):
  print(f"计算 {x} + {y}")
  return x + y


print("main start")
print(compute(1, 2))
print(compute(2, 3))
print(compute(3, 4))

print(compute(1, 2))
print(compute(3, 7))
print(compute(2, 2))
print(compute(4, 2))
print("main end")
